package com.shopoo.oauth.app;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.shopoo.dto.PageResponse;
import com.shopoo.dto.Response;
import com.shopoo.dto.SingleResponse;
import com.shopoo.exception.BizException;
import com.shopoo.oauth.api.RoleService;
import com.shopoo.oauth.app.assembler.AppAssembler;
import com.shopoo.oauth.app.converter.AppConverter;
import com.shopoo.oauth.domain.entity.Menu;
import com.shopoo.oauth.domain.entity.Role;
import com.shopoo.oauth.domain.entity.User;
import com.shopoo.oauth.domain.repository.MenuRepository;
import com.shopoo.oauth.domain.repository.MsgRepository;
import com.shopoo.oauth.domain.repository.PowerCacheRepository;
import com.shopoo.oauth.domain.repository.RoleMenuRepository;
import com.shopoo.oauth.domain.repository.RoleRepository;
import com.shopoo.oauth.domain.repository.UserRoleRepository;
import com.shopoo.oauth.dto.clientobject.MenuTree;
import com.shopoo.oauth.dto.clientobject.RoleDetailDTO;
import com.shopoo.oauth.dto.clientobject.RoleOption;
import com.shopoo.oauth.dto.clientobject.RoleRespDTO;
import com.shopoo.oauth.dto.cqe.RoleAddCmd;
import com.shopoo.oauth.dto.cqe.RolePowerUpdateCmd;
import com.shopoo.oauth.dto.cqe.RoleQuery;
import com.shopoo.oauth.dto.cqe.RoleUpdateCmd;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 角色表(TSystemRole)表服务实现类
 *
 * @author makejava
 * @since 2020-05-23 10:00:45
 */
@Service
public class RoleServiceImpl implements RoleService {

    @Resource
    private RoleRepository roleRepository;

    @Resource
    private PowerCacheRepository powerCache;

    @Resource
    private MsgRepository msgRepository;

    @Resource
    private RoleMenuRepository roleMenuRepository;

    @Resource
    private UserRoleRepository userRoleRepository;

    @Resource
    private MenuRepository menuRepository;

    @Transactional
    @Override
    public Response updatePower(RolePowerUpdateCmd rolePowerUpdateCmd) {
        Long roleId = rolePowerUpdateCmd.getRoleId();
        roleMenuRepository.deleteByRoleId(roleId);
        powerCache.removeAllRoleMenus();
        Long[] menuIds = rolePowerUpdateCmd.getMenuIds();
        roleMenuRepository.saveBatch(menuIds, roleId);
        refreshCache();
        return Response.buildSuccess();
    }

    /**
     * @Description: 缓存用户解锁
     * @Author: limy66
     * @Date:   2021/4/23 9:13
     * @Param:  [name]
     * @Return: void
     */
    @Override
    public Response cacheAllRoleMenus() {
        powerCache.removeAllRoleMenus();
        List<String> menus = roleMenuRepository.findAllRoleMenus();
        powerCache.cacheAllRoleMenus(menus);
        return Response.buildSuccess();
    }

    @Override
    public Response update(RoleUpdateCmd roleUpdateCmd) {
        Role role = AppConverter.INSTANCE.toRole(roleUpdateCmd);
        roleRepository.update(role);

        Long roleId = roleUpdateCmd.getRoleId();
        Long[] menuIds = roleUpdateCmd.getMenuIds();
        roleMenuRepository.deleteByRoleId(roleId);
        roleMenuRepository.saveBatch(menuIds, roleId);
        refreshCache();
        return Response.buildSuccess();
    }

    @Override
    public Response delete(Long roleId) {
        List<User> list = userRoleRepository.getByRoleId(roleId);
        if (list != null && list.size() > 0) {
            throw new BizException("该角色已经分配给其它用户，不能直接删除");
        }
        roleRepository.deleteById(roleId);
        roleMenuRepository.deleteByRoleId(roleId);
        return Response.buildSuccess();
    }

    @Override
    public Response save(RoleAddCmd roleAddCmd) {
        Role role = AppConverter.INSTANCE.toRole(roleAddCmd);
        Long roleId = System.currentTimeMillis();
        role.setRoleId(roleId);
        roleRepository.save(role);
        Long[] menuIds = roleAddCmd.getMenuIds();
        roleMenuRepository.saveBatch(menuIds, roleId);
        refreshCache();
        return Response.buildSuccess();
    }

    /**
     * @Description: 刷新权限并通知更新权限信息
     * @Author: limy66
     * @Date:   2021/5/18 9:43
     * @Param:  []
     * @Return: void
     */
    private void refreshCache() {
        powerCache.removeAllRoleMenus();
        List<String> menus = roleMenuRepository.findAllRoleMenus();
        powerCache.cacheAllRoleMenus(menus);
        msgRepository.sendUpdatePermission();
    }

    @Override
    public PageResponse findByConditions(RoleQuery roleQuery) {
        Page<Role> page = PageHelper.startPage(roleQuery.getPageNum() != null ? roleQuery.getPageNum() : 1, roleQuery.getPageSize() != null ? roleQuery.getPageSize() : 10);
        Role role = AppConverter.INSTANCE.toRole(roleQuery);
        roleRepository.findByConditions(role);
        return PageResponse.of(page.getResult(), page.getTotal(), page.getPageSize(), page.getPageNum());
    }

    @Override
    public SingleResponse<RoleRespDTO> findByUserId(String userId) {
        List<Role> list = roleRepository.findAllValidRole();
        Set<Long> roles = roleRepository.findRolesByUserId(userId);
        RoleRespDTO roleRespDTO = new RoleRespDTO();
        List<RoleOption> roleOptions = list.stream().map(oauthRole -> {return AppConverter.INSTANCE.toRoleOption(oauthRole);}).collect(Collectors.toList());
        roleRespDTO.setRoleOptions(roleOptions);
        roleRespDTO.setRoleIds(roles);
        return SingleResponse.of(roleRespDTO);
    }

    @Override
    public SingleResponse<RoleDetailDTO> findByRoleId(Long roleId) {
        Role role = roleRepository.getById(roleId);
        RoleDetailDTO roleDetailDTO = AppConverter.INSTANCE.toRoleDetailDTO(role);
        List<Menu> list = menuRepository.findAllValidMenu(roleId);
        List<MenuTree> menuTrees = AppAssembler.transferMenuTree(list, 0L);
        roleDetailDTO.setMenuTreeList(menuTrees);
        return SingleResponse.of(roleDetailDTO);
    }
}